﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.IO;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using SocketLib;
using System.Diagnostics;
using VideoCall.DataSetLocalTableAdapters;
struct User
{
    public int ID;
    public string username;
};
struct Group{
    public string gName;
    public int IDChuToa;
    public List<User> DanhSach;
};
namespace VideoCall
{
    public partial class FrmLogin : Form
    {
        #region Data
        DataProvider DuLieu = new DataProvider();
        #endregion

        #region Biến Port
        private int port = 1450;
        #endregion

        #region GROUP vs USER
        // Group
        int GroupCurrent;
        List<Group> ListGroup = new List<Group>();
        // User
        string listgroup = "";
        string UserList = "";
        List<User> ListUser = new List<User>();

        bool master = false;
        int numbermember;
        int slider = 1;
        int maxslider;
        int numberofslider = 5;
        #endregion

        #region ORTHER
        int YourID;
        Data msgReceived;
        bool show = false;
        #endregion
        
        #region FORM
        private frmUpdate _frmUpdate;
        private FrmVideoCall frmvideocall = new FrmVideoCall();
        #endregion

        #region SOCKET
        SocketLib.TCP.Client Client;
        #endregion
        
        public FrmLogin(frmUpdate frm)
        {
            InitializeComponent();
            _frmUpdate = frm;
            frmvideocall.Send += new FrmVideoCall.VideoCallGui(frmvideocall_Send);
            CheckForIllegalCrossThreadCalls = false;
        }

        #region Nhận Dữ liệu Từ Server
        void Client_RecieveData(object sender, TCP.RecieveDataTcpClientEventArgs e)
        {
            if (e.Data != null)
            {
                msgReceived = new Data(e.Data);
                switch (msgReceived.cmdCommand)
                {
                    case Command.UserNameError:
                        {
                            MessageBox.Show("UserName - Password Không hợp lệ", "VideoCall", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            Invoke(new MethodInvoker(delegate
                            {
                                Process[] processes = Process.GetProcessesByName("Video Conference Client");
                                foreach (Process process in processes)
                                    process.Kill();
                            }));
                            break;
                        }
                    case Command.Connect:
                        {
                            Invoke(new MethodInvoker(Process_Login));
                            break;
                        }
                    case Command.List:
                        {
                            Invoke(new MethodInvoker(Process_List));
                            break;
                        }
                    case Command.Chat:
                        {
                            Invoke(new MethodInvoker(delegate
                            {
                                frmvideocall.lsbshowchat.Items.Add(msgReceived.stringdata);
                            }));
                            break;
                        }
                    case Command.Calling:
                        {
                            Invoke(new MethodInvoker(delegate
                            {
                                Process_Calling(msgReceived.stringdata);
                            }));

                            break;
                        }
                    case Command.AnswerCalling:
                        {
                            // tắt nhạc call
                            frmvideocall.StopMusic();

                            frmvideocall.frmshowcall.Close();
                            break;
                        }
                    case Command.CancelCalling:
                        {
                            frmvideocall.frmcall.Close();
                            break;
                        }
                    case Command.StartGroup:
                        {
                            GroupCurrent = int.Parse(msgReceived.stringdata);
                            //Cap Nhat EndPointListCurrent & đưa list EndPointListCurrent sang formvideocall
                            Invoke(new MethodInvoker(UpdateGroupCurrent));
                            Invoke(new MethodInvoker(delegate {
                                frmvideocall.ActiveCall(this.GroupCurrent);
                            }));
                            
                            break;
                        }
                    case Command.Group:
                        {
                            frmvideocall.listgroup = msgReceived.stringdata;
                            this.listgroup = msgReceived.stringdata;
                            Invoke(new MethodInvoker(UpdateGroupList));
                            break;
                        }
                    case Command.No:
                        break;
                    case Command.Orther:
                        {
                            frmvideocall.Showmessage(msgReceived.stringdata);
                            break;
                        }
                    case Command.EndCall:
                        {
                            Invoke(new MethodInvoker(delegate
                            {
                                this.master = false;
                                this.frmvideocall.master = false;
                                this.slider = 1;
                                this.frmvideocall.slider = 1;
                                GroupCurrent = 0;
                                frmvideocall.DropCall();
                            }));
                            break;
                        }
                    case Command.JoinGroup:
                        {
                            Invoke(new MethodInvoker(pJoinGroup));
                            break;
                        }
                    case Command.AnswerJoin:
                        {
                            MessageBox.Show(msgReceived.stringdata);
                            break;
                        }
                    case Command.Bye:
                        {
                            MessageBox.Show("Mất Kết Nối Với Máy Chủ Chương Trình","VideoCall - Thông Báo",MessageBoxButtons.OK,MessageBoxIcon.Error);
                            Invoke(new MethodInvoker(delegate
                            {
                                Process[] processes = Process.GetProcessesByName("Video Conference Client");
                                foreach (Process process in processes)
                                    process.Kill();
                            }));
                            break;
                        }
                    case Command.MasterGroup:
                        {
                            Invoke(new MethodInvoker(delegate
                            {
                                this.master = true;
                                this.frmvideocall.master = true;
                            }));
                            break;
                        }
                    case Command.Slider:
                        {
                            Invoke(new MethodInvoker(delegate
                            {
                                this.slider = int.Parse(msgReceived.stringdata);
                                this.frmvideocall.slider = slider;
                                frmvideocall.refresh_picturebox();
                                frmvideocall.Current = 1;
                            }));
                            break;
                        }
                    case Command.RTP:
                        {
                            Invoke(new MethodInvoker(delegate
                            {
                                frmvideocall.Create_RTP_Muticast(msgReceived.stringdata);
                            }));
                            break;
                        }
                    case Command.File:
                        {
                            Invoke(new MethodInvoker(delegate
                            {
                                frmvideocall.portsendfile = int.Parse(msgReceived.stringdata);
                            }));
                            break;
                        }
                    case Command.AcceptFile:
                        {
                            Invoke(new MethodInvoker(delegate
                            {
                                Data msg = new Data(e.Data);
                                string[] temp = msg.stringdata.Split('*');
                                frmvideocall.SendFileToClient(temp[0], int.Parse(temp[1]));
                               
                            }));
                            break;
                        }
                }
            }
            else
                MessageBox.Show(null);
        }
        #endregion

        #region Nhận Dữ Liệu Từ FrmVideoCall
        void frmvideocall_Send(string data)
        {
            string[] temp = data.Split('|');
            switch (temp[0])
            {
                case "Bye": //ok
                    {
                       //SendCommand(Command.Bye, YourID + "*" + txtusername.Text);
                        Invoke(new MethodInvoker(delegate
                        {
                            Process[] processes = Process.GetProcessesByName("Video Conference Client");
                            foreach (Process process in processes)
                                process.Kill();
                        }));
                        this.Close();
                        break;
                    }
                case "Call": //ok
                    {
                        // chơi nhạc call
                        frmvideocall.PlayMusic("call", true);
                        SendCommand(Command.Calling, temp[1]);
                        break;
                    }
                case "ChangePassword": //ok
                    {
                        SendCommand(Command.ChangePassword, this.txtusername.Text +"*"+temp[1]);
                        break;
                    }
                case "AnswerCalling": //ok
                    {
                        // tắt chơi nhạc đang có cuộc gọi đến
                        frmvideocall.StopMusic();
                        foreach (User user in ListUser)
                        {
                            if (user.username == temp[2])
                            {
                                SendCommand(Command.AnswerCalling, temp[1] + "*" + user.ID.ToString());
                                break;
                            }
                        }
                        break;
                    }
                case "CancelCalling": // ok
                    {
                        SendCommand(Command.CancelCalling, temp[1]);
                        break;
                    }
                case "ChangeGroupCall":
                    {
                        break;
                    }
                case "Join":
                    {
                        SendCommand(Command.JoinGroup, temp[1] + "*" + txtusername.Text + "*" + YourID);
                        break;
                    }
                case "EndCall":
                    {
                        SendCommand(Command.EndCall, temp[1]);
                        break;
                    }
                case "Chat":
                    {
                        SendCommand(Command.Chat, temp[1]);
                        break;
                    }
                case "Slider":
                    {
                        SendCommand(Command.Slider,temp[1]+"*"+temp[2]);
                        break;
                    }
                case "SendFile":
                    {
                        SendCommand(Command.File, temp[1]);
                        break;
                    }
                case "AcceptFile":
                    {
                        SendCommand(Command.AcceptFile, temp[1]);
                        break;
                    }
            }
        }
        #endregion
        
        #region Cấu Trúc Dữ Liệu Gửi
        enum Command
        {
            No,
            Connect,
            UserNameError,
            Calling,
            EndCall,
            AnswerCalling,
            MasterGroup,
            Slider,
            CancelCalling,
            StartGroup,
            List,
            Group,
            JoinGroup,
            AnswerJoin,
            ChangePassword,
            RTP,
            File,
            AcceptFile,
            Orther,
            Chat,
            Bye,
            Null
        }
        class Data
        {
            public Data()
            {
                this.cmdCommand = Command.Null;
                this.stringdata = "";
            }

            //Converts the bytes into an object of type Data.
            public Data(byte[] data)
            {
                //The first four bytes are for the Command.
                this.cmdCommand = (Command)BitConverter.ToInt32(data, 0);

                //The next four store the length of the name.
                int nameLen = BitConverter.ToInt32(data, 4);

                //This check makes sure that strName has been passed in the array of bytes.
                if (nameLen > 0)
                    this.stringdata = Encoding.UTF8.GetString(data, 8, nameLen);
                else
                    this.stringdata = null;
            }

            //Converts the Data structure into an array of bytes.
            public byte[] ToByte()
            {
                List<byte> result = new List<byte>();

                //First four are for the Command.
                result.AddRange(BitConverter.GetBytes((int)cmdCommand));

                //Add the length of the name.
                if (stringdata != null)
                    result.AddRange(BitConverter.GetBytes(stringdata.Length));
                else
                    result.AddRange(BitConverter.GetBytes(0));

                //Add the name.
                if (stringdata != null)
                    result.AddRange(Encoding.UTF8.GetBytes(stringdata));

                return result.ToArray();
            }

            public Command cmdCommand;
            public string stringdata;
        }
        private void SendCommand(Command cmd, string stringdata)
        {
            try
            {
                //Create the message to send.
                Data msgToSend = new Data();

                msgToSend.cmdCommand = cmd;
                msgToSend.stringdata = stringdata;

                byte[] message = msgToSend.ToByte();
                Client.Send(message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "VideoCall-SendCommand ()", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        #endregion

        #region Nhấp Nút Kết Nối
        private void pictureBox1_Click(object sender, EventArgs e)
        {
            pictureBox1.Enabled = false;
            Connect(txtipserver.Text, this.txtusername.Text, this.txtpassword.Text);
        }
        private void FrmLogin_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
                Connect(txtipserver.Text, txtusername.Text, txtpassword.Text);
        }
        #endregion    
        
        #region NHÓM HÀM XỬ LÝ CHÍNH
        // Xử lý kết nối
        private void Connect(string ip, string username, string password)
        {
            try
            {
                Client = new TCP.Client(ip, port, 1024 * 5);
                Client.RecieveData +=new TCP.RecieveDataTcpClientEventHandler(Client_RecieveData);
                Client.ServerDisconnected += new TCP.ServerDisconnectedEventHandler(Client_ServerDisconnected);
                Client.Start();
                // lấy ip của máy mình
                IPHostEntry ipHost = Dns.Resolve(Dns.GetHostName());
                IPAddress ipAddr = ipHost.AddressList[0];
                SendCommand(Command.Connect, username + "*" + password + "*" + ipAddr.ToString());
                show = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show("!!! Không thể kết nối với máy chủ.", "VideoCall-Connect", MessageBoxButtons.OK, MessageBoxIcon.Error);
                pictureBox1.Enabled = true;
            }
        }
        // Xử lý ngắt kết nối với server
        void Client_ServerDisconnected(object sender, TCP.ServerDisconnectedEventArgs e)
        {
            // biet server bi dong ket noi
            MessageBox.Show("Mất kết nối với máy chủ","Server Disconnected",MessageBoxButtons.OK,MessageBoxIcon.Error);
            Process[] processes = Process.GetProcessesByName("VideoCall");
            foreach (Process process in processes)
                process.Kill();
        }
        // Xử lý khi đăng nhập
        public void Process_Login()
        {
            frmvideocall.username = txtusername.Text;
            IPHostEntry ipHost = Dns.Resolve(Dns.GetHostName());
            IPAddress ipAddr = ipHost.AddressList[0];
            frmvideocall.yourip = ipAddr.ToString();
            YourID = int.Parse(msgReceived.stringdata);
            frmvideocall.YourID = int.Parse(msgReceived.stringdata);
            frmvideocall.Show();
            this.Visible = false;
            YourID = int.Parse(msgReceived.stringdata);

            // chơi nhạc login
            frmvideocall.PlayMusic("login", false);   
        }
        // Xử lý danh sách user mới
        public void Process_List()
        {
            UserList = msgReceived.stringdata;
            frmvideocall.UpdateContacts(msgReceived.stringdata);
            UpdateListUser(UserList);
        }
        // Cập Nhật Danh sách user
        public void UpdateListUser(string usl)
        {
            string[] user = usl.Split(',');
            ListUser.Clear();
            for (int i = 0; i < user.Length; i++)
            {
                string[] part = user[i].Split('*');
                User us = new User();
                us.username = part[0];
                us.ID = int.Parse(part[1]);
                ListUser.Add(us);
            }
        }
        // Cập Nhật Group List
        public void UpdateGroupList()
        {
            // Hiện danh sách các group hiện tại lên tab Thao tác
            frmvideocall.UpDataListGroup();
            // Cập nhật lại danh sách các group
            ListGroup.Clear();
            // GroupName2?1,2,3*GroupName2?4,5,6
            if (listgroup != null)
            {
                string[] gp = msgReceived.stringdata.Split('*');
                for (int i = 0; i < gp.Length; i++)
                {
                    Group GP = new Group();
                    GP.DanhSach = new List<User>();
                    string[] onegp = gp[i].Split('?');
                    GP.gName = onegp[0];
                    string[] listclient = onegp[1].Split(',');
                    for (int j = 0; j < listclient.Length; j++)
                    {
                        User newus = new User();
                        newus.username = listclient[j];
                        GP.DanhSach.Add(newus);
                    }
                    ListGroup.Add(GP);
                }
            }
            UpdateGroupCurrent();
        }
        // Cập Nhật Group Đang Call Hiện Taị
        public void UpdateGroupCurrent()
        {
            string str = "";
            foreach (Group GP in ListGroup)
            {
                if (GP.gName == GroupCurrent.ToString())
                {
                    // cập nhật số lượng thanh viên trong group
                    this.numbermember = GP.DanhSach.Count;
                    this.frmvideocall.numbermember = GP.DanhSach.Count;
                    this.maxslider = GetMaxSlider(GP.DanhSach.Count);
                    this.frmvideocall.Maxslider = GetMaxSlider(GP.DanhSach.Count);
                    str += "Cuộc gọi " + GP.gName+" : ";
                    int number = 0;
                    foreach (User us in GP.DanhSach)
                    {
                        number++;
                        str += us.username+", ";
                        if (us.username == txtusername.Text)
                            frmvideocall.stt = number;
                    }
                }
            }
            frmvideocall.lbnamecallcurrent.Text = str;
            frmvideocall.lbnamecallcurrent.Visible = true;
        }
        // Hàm trả về số slider tối da
        public int GetMaxSlider(int number)
        {
            if (number % numberofslider > 0)
                return (number / numberofslider) + 1;
            return number / numberofslider;

        }
        // Chức năng gọi
        public void Process_Calling(string data)
        {
            // choi nhac dang co cuoc goi toi
            frmvideocall.PlayMusic("calling", true);

            foreach (User user in ListUser)
            {
                if (user.ID.ToString() == data)
                {
                    frmvideocall.ShowCalling(user.username);
                    break;
                }

            }
        }
        // Trả lời Join Group
        public void pJoinGroup()
        {
            // us.username*ID*gName*
            string[] user = msgReceived.stringdata.Split('*');

            if (MessageBox.Show(user[0] + " Muốn Tham Gia Vào Cuộc Gọi " + user[2] + " Mà Bạn làm Chủ Tọa", "VideoCall - Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                SendCommand(Command.AnswerJoin, "YES*" + YourID + "*" + user[2] + "*" + user[1]);
            else
                SendCommand(Command.AnswerJoin, "NO*" + YourID + "*" + user[2] + "*" + user[1]);
        }
        #endregion  

        #region Sự Kiện FormClosed
        private void FrmLogin_FormClosed(object sender, FormClosedEventArgs e)
        {
            frmvideocall.Mic.Stop();

            _frmUpdate.Close();
        }
        #endregion

        private void FrmLogin_Load(object sender, EventArgs e)
        {
            string IpServer = DuLieu.GetIPServer();
            if (IpServer == "null")
                txtipserver.Text = "Nhập IP Server";
            else
                txtipserver.Text = IpServer;
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox1.Checked == true)
            {
                if (txtipserver.Text != "")
                    DuLieu.UpdataIPServer(txtipserver.Text);
                else
                    MessageBox.Show("Địa chỉ Server không được bỏ trống", "VideoCall - Save IP Server", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        

    }
}
